#pragma once
#include <mqcomm/Log.hpp>
#include <mqcomm/Helper.hpp>
#include <mqcomm/Message.pb.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <cassert>
#include <google/protobuf/map.h>
using namespace std;


namespace rbmq {
    // 1、交换机类
    struct Exchange {
        using ptr = shared_ptr<Exchange>;
        Exchange() {

        }
        Exchange(const string& name, mqNs::ExchangeType type, bool durable, bool auto_delete, const google::protobuf::Map<string, string>& args) 
            :_name(name)
            ,_type(type)
            ,_durable(durable)
            ,_auto_delete(auto_delete)
            ,_args(args)
        {}
        string get_args() {
            if (_args.empty()) {
                return "";
            }
            // 将_args中的内容，序列化之后，返回一个字符串
            // 字符串形式: key=val&&key=val
            string ret;
            for (auto it = _args.begin(); it != _args.end(); it++) {
                ret += it->first + "=" + it->second + "&";
            }
            ret.pop_back();
            
            return ret;
        }

        void SetArgs(const string& args_str) { // 内部会解析args_str，然后放到unordered_map中去
            // key=val&key=val
            // 将字符串分割后，加入到unordered_map中
            vector<string> tokens;
            StringHelper::splitString(args_str, &tokens, "&");
            for (auto& str : tokens) {
                auto pos = str.find("=");
                string key = str.substr(0, pos);
                string val = str.substr(pos + 1);
                _args[key] = val;
            }
        }

        string _name; // 交换机名称
        mqNs::ExchangeType _type; // 交换机类型
        bool _durable; // 交换机持久化标志
        bool _auto_delete; // 是否自动删除标志
        // google::protobuf::Map<string, string> _args; // 其它参数
        google::protobuf::Map<string, string> _args;
    };
    // -------------------------------------------------------------------------------------------------------------------------------------------

    // 2、交换机数据持久化管理类
    class ExchangeMapper {
    public :
        typedef unordered_map<string, Exchange::ptr> ExchangeMap;
        ExchangeMapper(const string& dbfile) 
            :_sql_helper(dbfile)
        {
            // 创建数据库目录，获取dbfile的父级目录，并创建
            string path = FileHelper::parentDiretoty(dbfile);
            // 创建父路径
            if (FileHelper::createDirectory(path)) {
                // 打开或创建数据库
                assert(_sql_helper.open());
            }
            // 创建表
            createTable();
        }
        void createTable() { // 创建数据库表
            // 创建交换机表
            // 表中字段：交换机名称(主键)、交换机类型、持久化标志、删除标志、其它参数(args)
            const string commd = "create table if not exists exchange_table(name varchar(32) primary key, type int, durable int ,auto_delete int, args varchar(128));";
            // 执行语句创建表
            if (!_sql_helper.execute(commd, nullptr, nullptr) ) {
                LOG(Fatal) << "创建交换机数据表失败!" << endl;
                abort();
            }
            LOG(INfo) << "创建交换机数据库表成功!" << endl;
            
        }
        void removeTable() { // 删除数据库表
            const string commd = "drop table if exists exchange_table;";
            // 执行语句
            if (!_sql_helper.execute(commd, nullptr, nullptr) ) {
                LOG(Fatal) << "删除交换机数据表失败!" << endl;
                abort();
            }
        }

        void insert(Exchange::ptr& exchange) { // 新增交换机
            char commd[1024];
            string args_str = exchange->get_args();
            sprintf(commd, "insert into exchange_table(name, type, durable, auto_delete, args) values('%s', %d, %d, %d, '%s');", \
            exchange->_name.c_str(), exchange->_type, exchange->_durable, exchange->_auto_delete, args_str.c_str());
            // 执行语句
            if (!_sql_helper.execute(commd, nullptr, nullptr)) {
                LOG(Waring) << "添加数据到交换机数据表失败!" << endl;
            }
        }
        void remove(const string& ename) { // 删除一个交换机
            const string commd = "delete from exchange_table where name='" + ename + "';";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }

        // Exchange::ptr getOne(const string& ename) { // 获取单个交换机
        //     const string commd = "select name, type, durable, auto_delete, args from exchange_table where name='" + ename + "';";
        //     Exchange::ptr exp;
        //     // 执行语句
        //     _sql_helper.execute(commd, selectCallback, exp.get());
        //     return exp;
        // }
        unordered_map<string, Exchange::ptr> recovery() { // 获取所有的交换机(用于恢复交换机)
            ExchangeMap result;
            const string commd = "select name, type, durable, auto_delete, args from exchange_table;";
            // 执行语句
            _sql_helper.execute(commd, selectCallback, &result);
            return result;
        }
    private :
        static int selectCallback(void *arg, int numcol, char** row, char** feilds) {
            ExchangeMap *result = static_cast<ExchangeMap*>(arg);
            auto exp = make_shared<Exchange>();
            exp->_name = row[0];
            exp->_type = (mqNs::ExchangeType)stoi(row[1]);
            exp->_durable = (bool)stoi(row[2]);
            exp->_auto_delete = (bool)stoi(row[3]);
            if (row[4]) {
                exp->SetArgs(row[4]);
            }
            result->insert(make_pair(exp->_name, exp));
            return 0;
        }
    private :
        SqliteHelper _sql_helper; // 数据库句柄
    };
    // -------------------------------------------------------------------------------------------------------------------------------------
    
    // 3、交换机数据内存管理类
    class ExchangeManager {
    public :
        typedef shared_ptr<ExchangeManager> ptr;
        ExchangeManager(const string& dbfile)
            :_mapper(dbfile)
        {
            // 每次重启的时候，需要先回复历史数据
            unique_lock<mutex> lock(_mutex);
            _exchanges = _mapper.recovery();
        }
        // 声明交换机
        void declareExchange(const string& name, mqNs::ExchangeType type, bool durable, bool auto_delete, const google::protobuf::Map<string, string>& args) {
            unique_lock<mutex> lock(_mutex);
            // 如果不存在才需要加
            auto pos = _exchanges.find(name);
            if (pos != _exchanges.end()) {
                return;
            }
            // 创建一个交换机对象，放入unordered_map中
            Exchange::ptr exp = make_shared<Exchange>(name, type, durable, auto_delete, args);
            // 如果需要持久化存储，也要放到内存数据管理_mapper中
            if (durable == true) {
                _mapper.insert(exp);
            }
            _exchanges[name] = exp;
        }
        // 删除交换机
        void deleteExchange(const string& name) {
            unique_lock<mutex> lock(_mutex);
            // 不存在直接返回
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end()) {
                return ;
            }
            // 同样的，如果需要持久化存储, 那么还需要将_mapper中的交换机删除
            if (_exchanges[name]->_durable == true) {
                _mapper.remove(name);
            }
            _exchanges.erase(name);
        }

        // 获取一个交换机
        Exchange::ptr selectExchange(const string& name) {
            unique_lock<mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end()) {
                return Exchange::ptr();
            }
            return _exchanges[name];
        }

        bool exists(const string& name) { // 判断一个交换机是否存在
            unique_lock<mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end()) {
                return false;
            }
            return true;
        }

        void clear() { // 清理所有的交换机
            unique_lock<mutex> lock(_mutex);
            _mapper.removeTable();
            _exchanges.clear();
        }
        size_t size() {
            unique_lock<mutex> lock(_mutex);
            return _exchanges.size();
        }
    private :
        mutex _mutex; // 互斥锁
        ExchangeMapper _mapper; // 持久化的管理 
        unordered_map<string, Exchange::ptr> _exchanges; 
    };
};

